/***************************************************************************
 *                                                                         *
 *  This program is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation, either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 *					                                   *
 ***************************************************************************/
package jtwittconsolepackage;

import jTwittConsoleExceptions.IJTwittConsoleErrorTypes;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;

import jline.ConsoleReader;



/**
 * The center application is the heart element of jTwittConsole.
 * It manages the update, search and set timeline calls towards twitter.
 */
public class CenterApplication implements IJTwittConsoleErrorTypes
{
    private ColorManager colorManager;
    private PrettyPrinter prettyPrinter;
    private ConfigReader configReader; //TODO: use getInstance-method instead of object
    private Twitter twitter;
    
    private final static String version = "0.1.5.1";

    private final static String accessTokenFileName = "accessToken.ser";
    private final static String homeFolderAccessTokenPathExtension
            = "/.jTwittConsole/"; // slash at the end needed

    private final static String consumerKey = "YzEbmrLCwAEgArPES7uRqA";
    private final static String consumerSecret
            = "MCS5TeiD0vvCGhIfjYWvjm9X4K7rf1pUqqBWHvinkk";
    
    private final static String UPDATE_TYPE_NORMAL_TIMELINE = "NormalTimeline";
    private final static String UPDATE_TYPE_MENTIONS = "Mentions";
    private final static String UPDATE_TYPE_FAVORITES = "Favorites";

    private final static int MAXIMUM_TWEET_LENGTH = 140;
    private final static int NUMBER_OF_FETCHED_PAGES = 4;

    private final static String CONFIRM_KEY = "y";


    public CenterApplication()
    {
        //initializing other objects
        this.colorManager = new ColorManager();
        this.prettyPrinter = new PrettyPrinter();
        this.configReader = ConfigReader.getInstance();

        //reading the config file
        this.configReader.readConfigFile();

        //building a twitter object to post, read, etc. messages
        handleLogin();
    }

    /**
     * Checks if the user accepts the splitted messages and sends them if
     * accepted;
     * @param messages a list of the messages that potentially can be send
     * @throws IOException
     */
    private void checkConfirmationAndSetNewMessages(ArrayList<String> messages)
            throws IOException
    {
        System.out.println("\033[31mPress\"y\" to send:\033[0m");

        if (readFromConsole().equals(CONFIRM_KEY))
        {
            System.out.println("Sending messages...");
            for (int i = 0; i < messages.size(); i++)
            {
                String singleMessage = messages.get(i);

                //refresh the timeline only after the last send-process
                if (i == messages.size() - 1)
                {
                    setNewStatus(singleMessage, true);
                }
                else
                {
                    setNewStatus(singleMessage, false);
                }

                System.out.println("[" + i + "] send");
            }
            System.out.println("Sending done;");
        }
        else
        {
            System.out.println("Input aborted...");
        }
    }

    /**
     * creates an accessToken is there is non 
     * @param centerApp the centerApplication that needs the token
     */
    private void createAccessToken()
    {
        //if folder for access token does not exist -> create it
        if(!(new File(getCompleteAccessTokenPath())).exists())
        {
            (new File(getCompleteAccessTokenPath())).mkdir();
        }

        //no existing tokenFile -> create one
        if(!(new File(getCompleteAccessTokenPath() +
                accessTokenFileName)).exists())
        {
            try
            {
                //RequestToken only needed at first twitter-call
                RequestToken requestToken = twitter.getOAuthRequestToken();
                AccessToken accessToken = null;
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

                while (accessToken == null)
                {
                    System.out.println("First usage of application;");
                    System.out.println("The following steps are only needed once.");
                    System.out.println("Open the following URL and grant access to your account:");
                    System.out.println(requestToken.getAuthorizationURL());
                    System.out.print("Enter the PIN(if aviailable) or just hit enter.[PIN]:");
                    String pin = br.readLine();

                    try
                    {
                       if(pin != null && pin.length() > 0)
                       {
                         accessToken = twitter.getOAuthAccessToken(requestToken, pin);
                       }
                       else
                       {
                         accessToken = twitter.getOAuthAccessToken();
                       }
                    }
                    catch (TwitterException te)
                    {
                      if(401 == te.getStatusCode())
                      {
                    	  ErrorLogger.getInstance().exceptionOccured("Unable to get the access token.",
                                  Integer.valueOf(te.getStatusCode()).toString(),
                                  te, errorCodeHandleLogin);
                      }
                      else
                      {
                    	  ErrorLogger.getInstance().exceptionOccured("An error occured during authentication",
                                  Integer.valueOf(te.getStatusCode()).toString(),
                                  te, errorCodeHandleLogin);
                      }
                    }
                  }
                  //persist to the accessToken for future reference.
                  this.storeAccessToken(accessToken);
            }
            catch(Exception e)
            {
            	ErrorLogger.getInstance().exceptionOccured("An error occured during authentication",
                        "-1", e, errorCodeHandleLogin);
            }
        }
    }

    /**
     * Get the complete path to the access token
     * @return the complete path to the access token
     */
    private static String getCompleteAccessTokenPath()
    {
        return getHomeDirectoryPath() + homeFolderAccessTokenPathExtension;
    }
    
    /**
     * Get the path to the home directory of the current user;
     * @return homeDirectoryPath
     */
    private static String getHomeDirectoryPath()
    {
        return System.getProperty("user.home");
    }

    /**
     * Method treats login tokens. If there is no login token, then call the
     * function to create one.
     * Otherwise read the existing token.
     */
    private void handleLogin()
    {
        twitter = new TwitterFactory().getInstance();
        twitter.setOAuthConsumer(consumerKey, consumerSecret);

        //no existing tokenFile -> create one
        if(!(new File(getCompleteAccessTokenPath() +
                accessTokenFileName)).exists())
        {
            createAccessToken();
        }
        else //token file allready exists -> read the file
        {
            AccessToken accessToken = loadAccessToken();
            twitter.setOAuthAccessToken(accessToken);
        }
    }

    /**
     * Loads a former stored accessToken
     * @return the deserialized accessToken
     */
    private static AccessToken loadAccessToken()
    {
        AccessToken result = null;

        try
        {
            FileInputStream fis = new FileInputStream(getCompleteAccessTokenPath() +
                    accessTokenFileName);
            ObjectInputStream ois = new ObjectInputStream(fis);
            result = (AccessToken) ois.readObject();
            ois.close();
        }
        catch(Exception e)
        {
        	ErrorLogger.getInstance().exceptionOccured("An error occurred while loading access token",
                        "-1", e, errorCodeLoadAccessToken);
        }

        return result;
    }

    /**
     * Prints the most important keys and their meanings.
     */
    private void printBasicKeys()
    {
        System.out.println(configReader.getRefreshKey() + ": refresh timeline\t" +
            configReader.getNewMessageKey() + ": write message\t" +
            configReader.getQuitKey() + ": quit\t" +
            configReader.getHelpKey() + ": print help text");
    }

    /**
     * Prints a help text, including the keys and actual version.
     */
    private void printHelpText()
    {
        System.out.println();
        System.out.println("_Help_: Currently defined keys are");
        System.out.println(configReader.getRefreshKey() + ": refresh timeline");
        System.out.println(configReader.getNewMessageKey() + ": write new message");
        System.out.println(configReader.getMentionKey() + ": get timeline mentioning your username");
        System.out.println(configReader.getSearchKey() + ": search for tweets");
        System.out.println(configReader.getFavoriteKey() + ": favorites one tweet");
        System.out.println(configReader.getFavoriteListKey() + ": lists all favorited tweets");
        System.out.println(configReader.getRetweetKey() + ": retweets a message");
        System.out.println(configReader.getQuitKey() + ": quit jTwittConsole");
        System.out.println(configReader.getHelpKey() + ": this help");
        System.out.println("Current version of jTwittConsole: " + version);
    }
    
    /**
     * Function prints a line to know where the last read messages are.
     */
    private static void printReadLine()
    {
    	System.out.println("-------------------------------------------------"
                + "-------------------------------------");
    }

    private static void printReadLineAndAddionalText(String additionalText)
    {
        printReadLine();
        System.out.println(additionalText);
    }

    /**
     * Function prints a line of waves "~".
     */
    private void printWaveLine()
    {
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
                + "~~~~~~~~~~~~~~~~~~~~~~~~~");
    }

    /**
     * Method reads from console. (arrow-keys are fully functional)
     * @return the string read from console
     * @throws IOException
     */
    private String readFromConsole() throws IOException
    {
        String result;

        ConsoleReader consoleReader = new ConsoleReader();
        result = consoleReader.readLine(); //ToDo
        consoleReader = null;

        return result;
    }

    /**
     * Removes unwanted symbols from a status text;
     * @param statusText the text that shall be checked
     * @return the improved string
     */
    private String removeUnwantedSymbolsFromStatusString(String statusText)
    {
        //remove useless char sequences
        if (statusText.contains("\r\n"))
        {
            statusText = statusText.replace("\r\n", " ");
        }
        if (statusText.contains("\r\t"))
        {
            statusText = statusText.replace("\r\t", " ");
        }
        if (statusText.contains("\n"))
        {
            statusText = statusText.replace("\n", " ");
        }
        if (statusText.contains("\t"))
        {
            statusText = statusText.replace("\t", " ");
        }

        //because of string changes above -> several double blanks can
        //be created
        while(statusText.contains("  "))
        {
            statusText = statusText.replace("  ", " ");
        }

        return statusText;
    }
    
    /**
     * Retweets a specific tweet
     * @param tweetIdToRetweet id of the tweet to be retweeted
     */
    private void retweet(String tweetIdToRetweet, boolean refreshTimeline)
    {
        try
        {
            twitter.retweetStatus(new Long(tweetIdToRetweet));
        }
        catch (TwitterException ex)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occured while retweeting",
                    "-1", ex, errorCodeRetweetStatus);
        }
    }
    
    /**
     * Favorites a tweet
     * @param tweetIdToFavorite id of the tweet to be favorited
     */
    private void favorite(String tweetIdToFavorite)
    {
        try
        {
            twitter.createFavorite(new Long(tweetIdToFavorite));
        }
        catch (NumberFormatException e)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occured while favoriting",
                    "-1", e, errorCodeSetFavorite);
        }
        catch (TwitterException e)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occured while favoriting",
                    "-1", e, errorCodeSetFavorite);
        }
    }

    /**
     * Searching for a particular string in the whole twitter timeline
     * @param searchString the string which has to be searched
     */
    private void search(String searchString)
    {
        Query query = new Query(searchString);
        TweetRepository searchRepository = SearchRepository.getInstance();

        try
        {
            QueryResult result = twitter.search(query);
            //System.out.println("hits:" + result.getTotal());//removed from api
            //for (Tweet tweet : result.getTweets())
            for (int i = result.getTweets().size() - 1; i >= 0; i--)
            {
                Status status = result.getTweets().get(i);

               //api returns sometimes empty toUser
               if(result.getTweets().get(i).getInReplyToScreenName() != null)
               {
                    prettyPrinter.printWholeTwitterMessage(status.getUser().getName(),
                            colorManager.getColor(status.getUser().getName()),
                            status.getText(),
                            status.getCreatedAt().toString(),
                            result.getTweets().get(i).getInReplyToScreenName(),
                            "",new Long(status.getId()),
                            searchRepository);//no source app name
               }
               else
               {
                    prettyPrinter.printWholeTwitterMessage(status.getUser().getName(),
                            colorManager.getColor(status.getUser().getName()),
                            result.getTweets().get(i).getText(),
                            status.getCreatedAt().toString(),
                            "", "",
                            new Long(status.getId()), searchRepository);//no source app name
               }
            }
            printWaveLine();
            System.out.println("Check for status-msgs at " + DateUtils.now("HH:mm:ss")
                    + " | " + result.getTweets().size() + " tweets fetched | RepoCount: "
                    + searchRepository.getNumberOfStoredTweets());
        }
        catch (TwitterException te)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occurred", "-1",
                    te, errorCodeSearch);
        }
    }

    /**
     * Adds a new status to the twitter timeline
     * @param newStatus the status which has to be set
     * @param refreshTimeline determines if timeline has to updated after posting new status
     */
    private void setNewStatus(String newStatus, boolean refreshTimeline)
    {
        Status status = null;

        try
        {
            //new status not null and not longer than maximum
            if ((newStatus != null) && (newStatus.length() < MAXIMUM_TWEET_LENGTH))
            {
                status = twitter.updateStatus(newStatus);
                System.out.println("Successfully updated the status to [" + status.getText() + "].");
                
                if(refreshTimeline)
                {
                    //update timeline after sending new message
                    updateTimeline(UPDATE_TYPE_NORMAL_TIMELINE); 
                }
            }
            else
            {
            	if (newStatus == null)
                {
                    System.out.println("Input malformed! New status is null");
                }
                else
                {
                    System.out.println("Input malformed! More than 140 chars entered; Length was: "
                            + newStatus.length() + " characters");
                }
            }
        }
        catch (TwitterException ex)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occured",
                    Integer.valueOf(ex.getStatusCode()).toString(), ex, errorCodeSetNewStatus);
        }
    }

    /**
     * Skips chars which remain in stdin.
     * Afterwards there is no more char in stdin to read.
     */
    private void skipCharsFromStdin()
    {
        try
        {
            if (System.in.available() > 0)
            {
                System.in.skip(System.in.available());
            }
        }
        catch (IOException ex)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occured",
                    "-1", ex, errorCodeSkipCharsFromStdin);
        }
    }


    /**
     * The method splits a given user message to several messages the obey
     * the length of a tweet.
     * @param msg the message entered by the user
     * @return a list of messages the matcht the length of a tweet
     */
    private ArrayList<String> splitMessages(String msg)
    {
        ArrayList<String> messages = new ArrayList<String>();

        while (msg.length() > 0)
        {
            String partMessage = null;

            if (msg.length() > MAXIMUM_TWEET_LENGTH)
            {
                partMessage = msg.substring(0, MAXIMUM_TWEET_LENGTH);
                msg = msg.substring(MAXIMUM_TWEET_LENGTH,
                        msg.length());
            }
            else
            {
                partMessage = msg.substring(0, msg.length());
                msg = "";
            }

            messages.add(partMessage);
        }

        System.out.println("Read message(s):");
        int msgCounter = 0;
        for (String singleMessage : messages)
        {
            System.out.println("[" + msgCounter + "] " + singleMessage);
            msgCounter++;
        }

        return messages;
    }


    /**
     * Method to store the access token which has been acquired from twitter.
     * @param at the token that has to be stored
     */
    private void storeAccessToken(AccessToken accessToken)
    {
        try
        {
            FileOutputStream fos = new FileOutputStream(getCompleteAccessTokenPath()
                    + accessTokenFileName);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(accessToken);
            oos.close();
        }
        catch(IOException e)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occured",
                    "-1", e, errorCodeStoreAccessToken);
        }
    }


    /**
     * Get the timeline for the specified twitter account;
     * @param updateType defines which information should be displayed in the "timeline"
     */
    private void updateTimeline(String updateType)
    {    	
        try
        {
            TweetRepository tweetRepository = null;
            List<Status> statuses = new ArrayList<Status>();
            int fetchedMessagesCounter = 0;
            int numberOfFetchedPages = NUMBER_OF_FETCHED_PAGES;

            //get normal timeline
            if (updateType.equals(UPDATE_TYPE_NORMAL_TIMELINE))
            {
                //if there are not enough tweets then reduce the fetched pages
                while(twitter.getHomeTimeline(new twitter4j.Paging(numberOfFetchedPages)).isEmpty()
                        && numberOfFetchedPages > 0)
                {
                    numberOfFetchedPages--;
                }

                //go through all pages to fetch messages
                for(int i=0; i<numberOfFetchedPages; i++)
                {
                    List<Status> tempStatuses
                            = twitter.getHomeTimeline(new twitter4j.Paging(i+1));

                    //insert every message: needed because
                    //twitter.getFriendsTimeline(new twitter4j.Paging(i+1));
                    //returns a whole list of tweets
                    for(int j=0; j<tempStatuses.size(); j++)
                    {
                        statuses.add(tempStatuses.get(j));
                        fetchedMessagesCounter++;
                    }
                }
                
                tweetRepository = TimeLineRepository.getInstance();
            }
            else if(updateType.equals(UPDATE_TYPE_MENTIONS)) //get timeline for special user
            {
                statuses = twitter.getMentionsTimeline();
                fetchedMessagesCounter = statuses.size();
                tweetRepository = TimeLineRepository.getInstance();
            }
            else if(updateType.equals(UPDATE_TYPE_FAVORITES))
            {
            	//if there are not enough tweets then reduce the fetched pages
                while(twitter.getFavorites(numberOfFetchedPages).isEmpty()
                        && numberOfFetchedPages > 0)
                {
                    numberOfFetchedPages--;
                }

                //go through all pages to fetch messages
                for(int i=0; i<numberOfFetchedPages; i++)
                {
                    List<Status> tempStatuses = twitter.getFavorites(i+1);

                    //insert every message: needed because
                    //twitter.getFavorites(new twitter4j.Paging(i+1));
                    //returns a whole list of tweets
                    for(int j=0; j<tempStatuses.size(); j++)
                    {
                        statuses.add(tempStatuses.get(j));
                        fetchedMessagesCounter++;
                    }
                }
                
                tweetRepository = FavoriteRepository.getInstance();
            }
            
            //mark the current refresh run
            tweetRepository.increaseRefreshCounter();
           
            System.out.println("Showing friends timeline.");
            printWaveLine();

            for (int cnt = statuses.size() - 1; cnt >= 0; cnt--)
            {
                Status status = statuses.get(cnt);
            	String statusText
                        = removeUnwantedSymbolsFromStatusString(status.getText());
                
                prettyPrinter.printWholeTwitterMessage(status.getUser().getScreenName(),
                    colorManager.getColor(status.getUser().getScreenName()),
                    statusText,
                    status.getCreatedAt().toString(),
                    status.getInReplyToScreenName(),
                    status.getSource(),
                    new Long(status.getId()),
                    status.isFavorited(),
                    tweetRepository);
            }
            
            //remove old tweets from the repository
            tweetRepository.cleanUpOldTweets();
            
            printWaveLine();
            System.out.println("Check for status-msgs at "
                    + DateUtils.now("HH:mm:ss")
                    + " | " + fetchedMessagesCounter
                    + " tweets fetched | RepoCount: "
                    + tweetRepository.getNumberOfStoredTweets());
        }
        catch (TwitterException te)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occured"
                    + " while fetching the timeline",
                    Integer.valueOf(te.getStatusCode()).toString(), te,
                    errorCodeUpdateTimeline);
        }
        catch (NullPointerException npe)
        {
            ErrorLogger.getInstance().exceptionOccured("An error occured"
                    + " while fetching the timeline",
                    "-1", npe, errorCodeUpdateTimeline);
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        CenterApplication centerApp = new CenterApplication();
        
        //initially updating timeline
        centerApp.updateTimeline(UPDATE_TYPE_NORMAL_TIMELINE);
        centerApp.printBasicKeys();

        //overlay the normal input with a ConsoleReader
        //simply used to get rid of pressing the 'enter'-key
        try
        {
            ConsoleReader useNoEnterToSubmit = new ConsoleReader();
            useNoEnterToSubmit = null;
        }
        catch (IOException ex)
        {
            Logger.getLogger(CenterApplication.class.getName()).log(Level.SEVERE,
                    null, ex);
        }

        //endless loop
        while (true)
        {
            char userMode = ' ';

            try
            {
                userMode = (char) System.in.read();

                //determine what to do
                if(userMode == centerApp.configReader.getRefreshKey())
                {
                    printReadLineAndAddionalText("refreshing");
                    //get standard timeline
                    centerApp.updateTimeline(UPDATE_TYPE_NORMAL_TIMELINE); 
                }
                else if(userMode == centerApp.configReader.getNewMessageKey())
                {
                    printReadLineAndAddionalText("\033[31mWrite a new message(Ctrl-D to abort):\033[0m");
                    centerApp.skipCharsFromStdin();//skip remaining return symbol
                    String msg = null;

                    msg = centerApp.readFromConsole();

                    if(msg != null)//user might abort input, so don't update
                    {
                        ArrayList<String> messages = centerApp.splitMessages(msg);                        
                        centerApp.checkConfirmationAndSetNewMessages(messages);
                    }
                    else
                    {
                        System.out.println("Input aborted...");
                    }
                }
                else if(userMode == centerApp.configReader.getMentionKey())
                {
                    printReadLineAndAddionalText("Getting tweets mentioning your username...");
                    centerApp.updateTimeline(UPDATE_TYPE_MENTIONS);
                }
                else if(userMode == centerApp.configReader.getHelpKey())
                {
                    centerApp.printHelpText();
                    System.out.println();
                }
                else if(userMode == centerApp.configReader.getSearchKey())
                {
                    printReadLineAndAddionalText("\033[32mEnter your search"
                            + " string(Ctrl-D to abort):\033[0m");
                    centerApp.skipCharsFromStdin();//skip remaining return symbol
                    String searchString = null;
                    searchString = centerApp.readFromConsole();

                    if(searchString != null)//user might abort input, so don't search
                    {
                        centerApp.search(searchString);
                    }
                    else
                    {
                        System.out.println("Search aborted...");
                    }
                }
                else if(userMode == centerApp.configReader.getQuitKey())
                {
                    System.out.println("Exiting...");
                    return;
                }
                else if(userMode == centerApp.configReader.getRetweetKey())
                {
                    printReadLineAndAddionalText("\033[36mEnter the ID to"
                            + " retweet(Ctrl-D to abort):\033[0m");
                    centerApp.skipCharsFromStdin();//skip remaining return symbol
                    String retweetId = null;
                    retweetId = centerApp.readFromConsole();
                    
                    if(retweetId != null)//user might abort input
                    {
                        centerApp.retweet(retweetId, true);
                    }
                    else
                    {
                        System.out.println("Retweet aborted...");
                    }
                }
                else if (userMode == centerApp.configReader.getFavoriteKey())
                {
                    printReadLineAndAddionalText("\033[36mEnter the tweet ID to"
                            + " favorite(Ctrl-D to abort):\033[0m");
                    centerApp.skipCharsFromStdin();//skip remaining return symbol
                    String retweetId = null;
                    retweetId = centerApp.readFromConsole();

                    if (retweetId != null)//user might abort input
                    {
                        centerApp.favorite(retweetId);
                        System.out.println("Favorited tweet - done");
                    }
                    else
                    {
                        System.out.println("Favorite aborted...");
                    }
                }
                else if(userMode == centerApp.configReader.getFavoriteListKey())
                {
                    printReadLineAndAddionalText("getting favorites");
                    //get favorites timeline
                    centerApp.updateTimeline(UPDATE_TYPE_FAVORITES); 
                }
                else
                {
                    System.out.println("Wrong character");
                }
            }
            catch (IOException ex)
            {
            	ErrorLogger.getInstance().exceptionOccured("An error occured",
                        "-1", ex, errorCodeMain);
            }

            centerApp.printBasicKeys();
            
            //if return signal is in in-buffer, ignore it
            centerApp.skipCharsFromStdin();
        }
    }
}
